import datetime

from neomodel import db

from .models import Person, ContactRel
from dateutil import \
    parser  # pip install python-dateutil   # https://blog.csdn.net/qq_38412868/article/details/105624639
import pytz

utc = pytz.UTC
import time
import datetime


# 将时间字符串转换为10位时间戳，时间字符串默认为2017-10-01 格式 https://blog.csdn.net/u013069552/article/details/108567058
def datestr_to_timestamp(date, format_string="%Y-%m-%d"):
    time_array = time.strptime(date, format_string)
    time_stamp = int(time.mktime(time_array))
    return time_stamp


# 字符串转datetime https://www.cnblogs.com/alfred0311/p/7885349.html
def str_2_datetime(datestr='2021-10-12'):
    """

    :param datestr: 2021-10-12
    :return:
    """
    fmt = '%Y-%m-%d'
    return datetime.datetime.strptime(datestr, fmt)


def str_2_date(datestr='2021-10-12'):
    pass


def filter_nodes(node_type, name, status, permanent_residence, mobile, card_id):
    """
    筛选节点
    :param node_type: Person节点类 StructuredNode
    :param name: 用户姓名 StructuredNode
    :param status: 病人状态 1, 2, 3 str
    :param permanent_residence: 常驻地 str
    :param mobile: 电话号码 str
    :return:
    [node, node]
    """
    node_set = node_type.nodes  # 拿到一个类型的全部节点集合
    # 电话号码是唯一标识符，如果有就直接返回了
    # 电话，和卡号是唯一的直接获取
    if mobile:
        try:
            node = node_set.get(mobile=mobile)
            return [node.serialize]
        except node_type.DoesNotExist:
            not_found_msg = f'找不到电话号码为{mobile}的用户'
            return not_found_msg
    if status:
        node_set.filter(status=status)  # 状态是可选的

    if card_id:
        try:
            node = node_set.get(card_id=card_id)
            return [node.serialize]
        except node_type.DoesNotExist:
            not_found_msg = f'找不到卡号为{card_id}的用户'
            return not_found_msg
    # 状态作为筛选
    if status:
        node_set.filter(status=status)  # 状态是可选的

    # 姓名和地址可能是不全的， 可以作为搜索功能
    node_set.filter(permanent_residence__icontains=permanent_residence)
    node_set.filter(name__icontains=name)

    return [node.serialize for node in node_set]


########################数据库虚假数据库构建################333


def create_rel(o_node_id, s_node_id, rel_info):
    """
    :param s_mobile: 手机号
    :param o_mobile:  手机号
    :param rel_info:  关系信息
        {
            'location_id' : '1',
            'degree' : '3',
            'time' : datetime类型,
        }
    :return:
    """
    o_person = Person.nodes.get_or_none(node_id=o_node_id)
    s_person = Person.nodes.get_or_none(node_id=s_node_id)

    if not bool(all([s_person, o_person])):
        return {'code': '201', 'msg': '有用户没找到'}

    rel_info['time'] = str_2_datetime(rel_info.get('time'))
    rel = s_person.contact.connect(o_person, rel_info)  # Expected node of class Person
    return {
        'nodes': [
            s_person.serialize,
            o_person.serialize,
        ],
        'edges': rel.serialize
    }


def create_rel_by_mobile(s_mobile, o_mobile, rel_info):
    """
    :param s_mobile: 手机号
    :param o_mobile:  手机号
    :param rel_info:  关系信息
        {
            'location_id' : '1',
            'degree' : '3',
            'time' : datetime类型,
        }
    :return:
    """
    s_person = Person.nodes.get_or_none(mobile=s_mobile)
    o_person = Person.nodes.get_or_none(mobile=o_mobile)
    if not bool(all([s_person, o_person])):
        return

    rel_info['time'] = str_2_datetime(rel_info.get('time'))
    rel = s_person.contact.connect(o_person, rel_info)  # Expected node of class Person
    return {
        'nodes': [
            s_person.serialize,
            o_person.serialize,
        ],
        'edges': rel.serialize
    }


def get_network(node_id='191', start_time='1999-01-01', end_time='2099-01-01'):
    """
    todo 最难的地方在这里，根据电话号码，时间之类的东西查询这个接触网络
    :param node_id: 电话号码
    :param start_time: 开始时间 str 时间字符串
    :param end_time: 结束时间 str
    :return:
    {
        nodes : [
            接触了那些人
        ]`
        edges : [
            所有的关系图
        ]
    }
    """
    if not start_time:
        start_time = '1999-01-01'
    if not end_time:
        end_time = '2099-01-01'
    start_timestamp = datestr_to_timestamp(start_time)
    end_timestamp = datestr_to_timestamp(end_time)

    result = {'nodes': [], 'edges': []}

    node_list = []
    rel_list = []

    rel_set = set()
    node_set = set()
    cypher = f"""MATCH p=(p1:Person{{node_id:{node_id}}})-[r:CONTACT *1..2]-() RETURN p  """
    print(cypher)
    rows, meta = db.cypher_query(cypher)

    for row in rows:
        path = row[0]
        # 拿到这个路径的的全部关系和节点
        rels = path.relationships
        # 为要对所有的关系进行判断
        for rel in rels:
            if rel.get('time') < start_timestamp or rel.get('time') > end_timestamp:
                continue
        # 存东西
        nodes = path.nodes
        for rel in rels:
            rel_set.add(rel)
        for node in nodes:
            node_set.add(node)

    for node in node_set:
        node_list.append(Person.inflate(node).serialize)

    for rel in rel_set:
        rel_list.append(ContactRel.inflate(rel).serialize)

    result['nodes'] = node_list
    result['edges'] = rel_list
    return result


if __name__ == '__main__':
    get_network()
    pass
